#include "ai.h"
#include "log.h"

#define RIGHT 1.0f
#define LEFT -1.0f
#define STRAIGHT 0.0f

////////////////////////////////////////////////////////////////////////////////

void DumbAI::think(const AIData& data, MicrobeOrder* orders[SIM_MAX_MICROBES],
    int dM, float dT)
{
  const Microbe* microbe = data.microbe[0];
  MicrobeOrder* order = orders[0];
  
  if (microbe->type == MICROBE_SPEEDY)
  {
    order->evolve = true;
  }
  else if (microbe->type == MICROBE_SOLDIER)
  {
    order->evolve = true;
  }
  else
  {
    if (data.num_enemies > 0)
    {
      int enemy_index = 0;
      float min_dis = Vector2_dis(microbe->body.pos, data.enemy[0]->body.pos);
      
      for (unsigned i = 1; i < data.num_enemies; i++)
      {
        float dis = Vector2_dis(microbe->body.pos, data.enemy[i]->body.pos);
        
        if (dis < min_dis)
        {
          min_dis = dis;
          enemy_index = i;
        }
      }
      
      Vector2 d = data.enemy[enemy_index]->body.pos - microbe->body.pos;
      
      order->attack = true;
      order->angle = d.angle();
    }
    else if (data.num_food > 0)
    {
      int food_index = 0;
      float min_dis = Vector2_dis(microbe->body.pos, data.food[0]->pos);
      
      for (unsigned i = 0; i < data.num_food; i++)
      {
        float dis = Vector2_dis(microbe->body.pos, data.food[i]->pos);
        
        if (dis < min_dis)
        {
          min_dis = dis;
          food_index = i;
        }
      }
      
      Vector2 d = data.food[food_index]->pos - microbe->body.pos;
      
      order->move = 1.0f;
      order->angle = d.angle();
    }
    else
    {
      
    }
  }
};

////////////////////////////////////////////////////////////////////////////////

ExampleAI::ExampleAI()
{
  state.type = EXAMPLE_STATE_NORMAL;
}

void ExampleAI::think(const AIData& data, MicrobeOrder* order[SIM_MAX_MICROBES],
  int dM, float dT)
{
  transitionState(data);
  executeState(data, order);
}

void ExampleAI::transitionState(const AIData& data)
{
  const Rectf& bounds = data.bounds;
  const Microbe* microbe = data.microbe[0];
  const Vector2& pos = microbe->body.pos;
  const float angle = microbe->angle;
  const float safety_dis = 48.0f;
  
  if (state.type == EXAMPLE_STATE_NORMAL)
  {
    if (pos.x - bounds.min_x < safety_dis && angle > 90.0f && angle < 270.0f)
    {
      state.type = EXAMPLE_STATE_AVOID_WALL;
      state.angle = Math_angleWrap360(Rand_float(-80.0f, 80.0f));
    }
    else if (pos.y - bounds.min_y < safety_dis && angle > 180.0f && angle < 360.0f)
    {
      state.type = EXAMPLE_STATE_AVOID_WALL;
      state.angle = Rand_float(10.0f, 170.0f);
    }
    else if (bounds.max_x - pos.x < safety_dis && (angle < 90.0f || angle > 270.0f))
    {
      state.type = EXAMPLE_STATE_AVOID_WALL;
      state.angle = Rand_float(100.0f, 260.0f);
    }
    else if (bounds.max_y - pos.y < safety_dis && angle > 0.0f && angle < 180.0f)
    {
      state.type = EXAMPLE_STATE_AVOID_WALL;
      state.angle = Rand_float(190.0f, 350.0f);
    }
  }
  else if (state.type == EXAMPLE_STATE_AVOID_WALL)
  {
    if (Math_angleCmp(microbe->angle, state.angle, 3.0f))
    {
      state.type = EXAMPLE_STATE_NORMAL;
    }
  }
}

void ExampleAI::executeState(const AIData& data,
  MicrobeOrder* order[SIM_MAX_MICROBES])
{
  const Microbe* microbe = data.microbe[0];
  
  if (state.type == EXAMPLE_STATE_NORMAL)
  {
    order[0]->turn = 0.0f;
  }
  else if (state.type == EXAMPLE_STATE_AVOID_WALL)
  {
    if (Math_angleWrap180(microbe->angle - state.angle) > 0.0f)
    {
      order[0]->turn = -1.0f;
    }
    else
    {
      order[0]->turn = 1.0f;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////

SmokeyAI::SmokeyAI()
{
  right = true;
  time = 0.0f;
}

void SmokeyAI::think(const AIData& data, MicrobeOrder* order[SIM_MAX_MICROBES],
    int dM, float dT)
{
  
}

void SmokeyAI::thinkSpeedy(const AIData& data, MicrobeOrder* order, float dT)
{
  Vector2 m_v(0, 0), f_v(0, 0), temp_v(0, 0), temp(0,0);
  float f_angle = 0.0, m_angle = 0.0;
  float distance = 0.0, temp_distance = 0.0;
  float safety_distance = 100;
  
  //Find info about the SPEEDY MICROBE
  m_v = data.microbe[0]->body.pos;
  m_angle = data.microbe[0]->angle;
  
  if(data.num_food > 0)
  {
    temp_distance = Vector2_dis(m_v, data.food[0]->pos);
    f_v = data.food[0]->pos;
    
    for(unsigned i = 1; i < data.num_food; i++)
    {
      temp_v = data.food[i]->pos;
      distance = Vector2_dis(m_v, temp_v);
        
      if(distance < temp_distance)
      {
       temp_distance = distance;
       f_v = temp_v;   
      }      
    }
    
    temp = f_v - m_v;
    f_angle = temp.angle();
    
    if(Math_cmp(m_angle, f_angle, 5.0f))
    {
      order->turn = STRAIGHT;
    }
    else if((m_angle > f_angle) && ((m_angle - f_angle) <= 180) && ((m_angle - f_angle) >= 0))
    {
      order->turn = LEFT;
    }
    else
    {
      order->turn = RIGHT;
    }
  }
  else
  {
    if(((m_v.x - data.bounds.min_x) < safety_distance) && (m_angle >= 180) && (m_angle < 270))
    {
      order->turn = RIGHT;      
    }
    else if(((m_v.x - data.bounds.min_x) < safety_distance) && (m_angle < 180) && (m_angle > 90))
    {
      order->turn = LEFT;      
    }
    else if(((m_v.y - data.bounds.min_y) < safety_distance) && (m_angle >= 270))
    {
      order->turn = RIGHT;      
    }
    else if(((m_v.y - data.bounds.min_y) < safety_distance) && (m_angle < 270) && (m_angle > 180))
    {
      order->turn = LEFT;      
    }
    else if(((data.bounds.max_x - m_v.x) < safety_distance) && (m_angle < 90))
    {
      order->turn = RIGHT;      
    }
    else if(((data.bounds.max_x - m_v.x) < safety_distance) && (m_angle > 270))
    {
      order->turn = LEFT;      
    }
    else if(((data.bounds.max_y - m_v.y) < safety_distance) && (m_angle >= 90) && (m_angle < 180))
    {
      order->turn = RIGHT;      
    }
    else if(((data.bounds.max_y - m_v.y) < safety_distance) && (m_angle < 90))
    {
      order->turn = LEFT;      
    }
    else
    {
      order->turn = STRAIGHT;
    }
  }
  
  //Reproduce after you have 60 food
  if(data.player_food >= 60)
  {
    order->reproduce = true;
  }
  else
  {
    order->reproduce = false;
  }
  
  //Log_print("angle[%f], dir[%f]\n", m_angle, order->dir);
}

/* ***Just For Reference***

struct Food
{
  unsigned id;
  bool alive;
  Vector2 pos;
};

Circle
  Vector2 pos;
  float radius;
  
struct Microbe
{
  MicrobeType type;
  unsigned id;
  unsigned player_id;
  Circle body;
  float angle;
  bool alive;
};

struct SpeedyMicrobeOrder
{
  float dir;
};

struct AIData
{
  Rectf bounds;
  int player_food;
  unsigned num_food;
  const Food* food[SIM_MAX_FOOD];
  const Microbe* microbe;
  unsigned num_enemies;
  const Microbe* ememies[SIM_MAX_MICROBES];
};*/

////////////////////////////////////////////////////////////////////////////////

ChrisAI::ChrisAI()
{
  state.type = CHRIS_STATE_NORMAL;
}

void ChrisAI::think(const AIData& data, MicrobeOrder* order[SIM_MAX_MICROBES],
  int dM, float dT)
{
  for (unsigned i = 0; i < data.num_microbes; i++)
  {
    transitionState(data);
    executeState(data, data.microbe[i], order[i]);
  }
}

void ChrisAI::transitionState(const AIData& data)
{
  //const Rectf& bounds = data.bounds;
  //const Microbe* microbe = data.microbe[0];
  //const Vector2& pos = microbe->body.pos;
  //const float angle = microbe->angle;
  //const float safety_dis = 40.0f;
  
  if (state.type == CHRIS_STATE_NORMAL)
  {
    
  }
}

void ChrisAI::executeState(const AIData& data, const Microbe* microbe,
    MicrobeOrder* order)
{
  if (state.type == CHRIS_STATE_NORMAL)
  {
    if (microbe->type == MICROBE_SPEEDY)
    {
      order->evolve = true;
    }
    else
    {
      bool can_attack = false;
      
      for (unsigned i = 0; i < data.num_food; i++)
      {
        if (Microbe_canSoldierAttack(microbe, data.food[i]))
        {
          can_attack = true;
          
          break;
        }
      }
      
      for (unsigned i = 0; i < data.num_enemies; i++)
      {
        if (Microbe_canSoldierAttack(microbe, data.enemy[i]))
        {
          can_attack = true;
        }
      }
      
      //if (data.player_food >= 50)
      //{
      //  order->reproduce = true;
      //}
      //else
      if (can_attack)
      {
        order->attack = true;
      }
      else
      {
        order->turn = 0.3f;
        order->move = 1.0f;
      }
    }
  }
}
